# @Author:黄景涛
# @Date: 2023/10/9
import random
from functools import wraps

from faker import Faker


fk = Faker(locale='zh_CN')


""" 组织架构 """
# 根组织配置：xx集团
company_name = '金鑫'
group_organizate_name = f'{company_name}工业集团'

# 一级组织配置：大区
regions = ('南部大区', '北部大区', '中部大区', '西部大区', '东部大区')
# regions = ('南部大区',)      # 调试
one_organizate_names = [company_name + item for item in regions]


# 二级组织配置：分公司
# 生成选中的国家中，城市名
two_organizate_names = []
# two_organizate_counts = 175
two_organizate_counts = 30  # 调试

i = 0
while i < two_organizate_counts:
    # city_name = f'{company_name}{fk.city_name() + random.choice("ABCDEFGHIJKLMNOPQRSTUVWXYZ")}分公司'
    city_name = f'{company_name}{fk.city_name()}分公司'
    if city_name not in two_organizate_names:
        two_organizate_names.append(city_name)
        i += 1

# 三、四、五级组织配置：中心 -> 部门 -> 小组
center_keywords = {'研发': ['设计', '生产', '测试', '产品', '开发'],
                   '销售': ['销售运营', '渠道推广', '客户关系维护'],
                   '市场': ['营销策划', '市场推广', '市场调研', '市场竞价'],
                   '技术服务': ['软件服务', '硬件服务'],
                   '客服': ['人工客服', 'AI客服', '通用客服'],
                   '人力资源': ['人力统筹', '人力分配', '人力跟踪', '人员考勤'],
                   '行政': ['前台行政', '日常行政'],
                   '战略规划': ['短期战略', '长期战略'],
                   '管理': ['财务', '流程', '总经办'],
                   '员工关怀': ['员工生日']}

# center_keywords = {'研发': ['设计', '生产']}        # 调试

five_kv = (
    (1, '一'), (2, '二'), (3, '三'), (4, '四'), (5, '五'), (6, '六'), (7, '七'), (8, '八'), (9, '九'), (10, '十'), (11, '十一'),
    (12, '十二'), (13, '十三'), (14, '十四'), (15, '十五'), (16, '十六'), (17, '十七'), (18, '十八'), (19, '十九'), (20, '二十'))
# DEBUG_COUNTS = 20
DEBUG_COUNTS = 5  # 调试
numbers_map = {k: v for k, v in five_kv[:DEBUG_COUNTS]}
# 叶子组织下的用户数量
FIVE_USER_LIMIT = 7


class Node:
    """组织: 以链表形式存储"""

    def __init__(self, name):
        """
        :param name: 组织架构树的根节点，虚拟节点
        :user_limit: 组织下，已挂载人员数量
        :unused_limit: 组织下，剩余可挂载人员数量
        :id: 组织id
        :parent: 父级组织id
        :childrens: 子级组织id列表
        """
        self.name = name
        self.user_limit = 1
        self.id = None
        self.parent = None
        self.childrens = []


# 构造链表：组织架构的n叉树
def create_organization():
    # 创建虚拟的根节点
    root_node = Node('root')

    # 创建集团
    group_node = Node(group_organizate_name)
    group_node.parent = root_node
    root_node.childrens.append(group_node)

    for idx, one in enumerate(one_organizate_names, 1):
        # 创建一级组织节点
        one_node = Node(one)
        # 一级组织的父节点属性
        one_node.parent = group_node
        # 将一级组织节点，添加到根节点的childrens属性中
        group_node.childrens.append(one_node)
        """"分公司，均分给每个大区"""
        multiple = two_organizate_counts // len(one_organizate_names)
        for two in two_organizate_names[multiple * (idx - 1): multiple * idx]:
            # 创建二级组织节点
            two_node = Node(two)
            two_node.parent = one_node
            one_node.childrens.append(two_node)
            for k, v in center_keywords.items():
                three = f'{k}中心'
                # k : 创建三级组织节点
                three_node = Node(three)
                three_node.parent = two_node
                two_node.childrens.append(three_node)
                for v_item in v:
                    four = f'{v_item}部门'
                    # v : 创建四级组织节点
                    four_node = Node(four)
                    four_node.parent = three_node
                    three_node.childrens.append(four_node)
                    for i in range(1, len(numbers_map) + 1):
                        five = f'{v_item}{numbers_map.get(i)}组'
                        # 创建五级组织节点
                        five_node = Node(five)
                        five_node.parent = four_node
                        # 五级组织的用户数量属性
                        five_node.user_limit = FIVE_USER_LIMIT
                        four_node.childrens.append(five_node)

    #  返回链表的根节点
    return root_node


# 统计函数调用次数
def count_calls(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        """
        类只存在一个，推导可得，类属性不受实例个数影响，也只存在一个，可视为类层级上的全局变量。
        所以，每次wrapper实例化，num_calls都是一个全局变量，可达到值累计效果
        """
        wrapper.num_calls += 1
        func(*args, **kwargs)

    """
    只在装饰时初始化一次，赋值为0
    函数的一等对象特性：当作类对象看待，给函数添加类属性num_calls
    """
    wrapper.num_calls = 0
    return wrapper


# DFS遍历
@count_calls
def dfs(current_node: Node, depth=0):
    if not current_node:
        return

    # 遍历当前节点
    msg = f'\t' * depth + f'层级：{depth}\t组织名称：{current_node.name}\t人员数量：{current_node.user_limit}\t组织id：{current_node.id}\t子组织：{[c.name for c in current_node.childrens]}'
    if current_node.name != "root":
        msg += f'\t父组织：{current_node.parent.name}'
    print(msg)
    # 遍历子节点
    for child in current_node.childrens:
        dfs(child, depth + 1)


if __name__ == '__main__':
    root = create_organization()
    counts = 0
    dfs(root)
    print(f'总数：{dfs.num_calls}')
